feat(aws-codepipeline): make input and output artifact names optional when creating Actions#845
Conversation
|
I'm in favor of changing to |
| * @returns the newly created {@link PipelineBuildAction} build Action | ||
| */ | ||
| public addBuildToPipeline(stage: codepipeline.IStage, name: string, props: CommonPipelineBuildActionProps): PipelineBuildAction { | ||
| public addBuildToPipeline(stage: codepipeline.IStage, name: string, props?: CommonPipelineBuildActionProps): PipelineBuildAction { |
| * @returns the newly created {@link PipelineSourceAction} | ||
| */ | ||
| public addToPipeline(stage: actions.IStage, name: string, props: CommonPipelineSourceActionProps): PipelineSourceAction { | ||
| public addToPipeline(stage: actions.IStage, name: string, props?: CommonPipelineSourceActionProps): PipelineSourceAction { |
|
|
||
| protected addOutputArtifact(name: string): Artifact { | ||
| const artifact = new Artifact(this, name); | ||
| protected addOutputArtifact(name?: string): Artifact { |
There was a problem hiding this comment.
You can instead do:
protected addOutputArtifact(name: string = this.stage._generateOutputArtifactName(this)) {
const artifact = new Artifact(this, outputArtifactName);
retenu artifact;
}There was a problem hiding this comment.
I don't think that will work. I want to call this method from the Action subclasses with props.outputArtifactName, where outputArtifactName is an optional string.
There was a problem hiding this comment.
I think @RomainMuller is right, you should be able to do that. If you pass undefined to name (which will be the case if props.outputArtifactName is not defined, it will apply the default.
There was a problem hiding this comment.
I stand corrected :) will change.
|
|
||
| protected addInputArtifact(artifact: Artifact): Action { | ||
| this._inputArtifacts.push(artifact); | ||
| protected addInputArtifact(artifact?: Artifact): Action { |
There was a problem hiding this comment.
Similar sugaring tip as before applies there.
There was a problem hiding this comment.
Same reply as above (I'm actually using the optional parameter).
| } | ||
|
|
||
| public _generateOutputArtifactName(action: actions.Action): string { | ||
| return (this.pipeline as any)._generateOutputArtifactName(this, action); |
There was a problem hiding this comment.
Honestly I don't like having to do this. I'd rather actually make the methods public & mark them s internal-use-only, which is already semi-obvious from their _-prepended names.
There was a problem hiding this comment.
Does it make much difference though?
There was a problem hiding this comment.
Main difference is the compiler stops trying to help the moment you've done as any, so you might miss breaking changes if you rename stuff & there is no test coverage through there.
| private _generateOutputArtifactName(stage: actions.IStage, action: actions.Action): string { | ||
| // for now, just return a generic output artifact, | ||
| // ignoring the names of both the Stage, and the Action | ||
| return 'Artifact_' + (++this.artifactsCounter); |
There was a problem hiding this comment.
The drawback is that this makes artifact names dependent on generation order. This means a user refactoring code & trying to ensure they didn't inadvertently change their infrastructure cannot rely on a simple diff test.
I would like this to be order-independent unless we have a very good reason why it's better otherwise (I understand this is a simplicity vs. user-friendliness tradeoff).
There was a problem hiding this comment.
I see. What would you see as the artifact name then? Some combination of Stage & Action names? `Artifact_${stage.name}_${action.name}`?
There was a problem hiding this comment.
We can use the uniqueId of the construct.
There was a problem hiding this comment.
One disadvantage of this: the artifact names are now super ugly (Artifact_awscdkcodepipelinecodecommitcodebuildMyBuildProjectbuild61B48DC4).
|
|
||
| // ignore unused private method (it's actually used in Stage) | ||
| // @ts-ignore | ||
| private _findInputArtifactFor(stage: actions.IStage, action: actions.Action): actions.Artifact { |
There was a problem hiding this comment.
The defaulting behavior that involves this particular element has a caveat that changing the runOrder after the defaulting behavior has happened will cause incorrect values to be used... A solutions is to make the runOder immutable & set at construction time?
There was a problem hiding this comment.
Yep. Not sure if it's a huge deal, as you can always name the artifacts directly, but I'm fine with making runOrder immutable (the rest of the properties of Actions already are).
Actually, that's a great point. The issue is that |
| * | ||
| * @default an auto-generated name will be used | ||
| */ | ||
| artifactName?: string; |
There was a problem hiding this comment.
+1 on changing this to outputArtifactName
| */ | ||
| public addBuildToPipeline(stage: codepipeline.IStage, name: string, props: CommonPipelineBuildActionProps): PipelineBuildAction { | ||
| public addBuildToPipeline(stage: codepipeline.IStage, name: string, props?: CommonPipelineBuildActionProps): PipelineBuildAction { | ||
| return new PipelineBuildAction(this.parent!, name, { |
There was a problem hiding this comment.
change this.parent! to this please
| */ | ||
| public addToPipeline(stage: actions.IStage, name: string, props: CommonPipelineSourceActionProps): PipelineSourceAction { | ||
| public addToPipeline(stage: actions.IStage, name: string, props?: CommonPipelineSourceActionProps): PipelineSourceAction { | ||
| return new PipelineSourceAction(this.parent!, name, { |
| * | ||
| * @param action the Action to generate the output artifact name for | ||
| */ | ||
| _generateOutputArtifactName(action: Action): string; |
There was a problem hiding this comment.
I wonder if it would be more elegant to hide all these internal methods under some _internal scope:
interface IStageInternal {
attachAction(...);
generateOutputArtifactName(...);
findInputArtifactFor(...);
};
interface IStage {
// public API
// internal API
_internal: IStageInternal;
}|
|
||
| protected addOutputArtifact(name: string): Artifact { | ||
| const artifact = new Artifact(this, name); | ||
| protected addOutputArtifact(name?: string): Artifact { |
There was a problem hiding this comment.
I think @RomainMuller is right, you should be able to do that. If you pass undefined to name (which will be the case if props.outputArtifactName is not defined, it will apply the default.
| if (props.artifactName) { | ||
| this.artifact = this.addOutputArtifact(props.artifactName); | ||
| } | ||
| this.artifact = this.addOutputArtifact(props.artifactName); |
There was a problem hiding this comment.
This is a change in behavior. This means that now BuildAction will always have an output artifact defined for it. Could be totally fine, but what happens if the CodeBuild project doesn't specify any artifacts in buildspec.yaml but you still define an output artifact?
There was a problem hiding this comment.
Good call out. I'll check what happens.
There was a problem hiding this comment.
Confirmed it doesn't cause any problems - there simply is no output artifact produced from the CodeBuild Project in this case, but the build Action itself succeeds without issues.
| private _generateOutputArtifactName(stage: actions.IStage, action: actions.Action): string { | ||
| // for now, just return a generic output artifact, | ||
| // ignoring the names of both the Stage, and the Action | ||
| return 'Artifact_' + (++this.artifactsCounter); |
There was a problem hiding this comment.
We can use the uniqueId of the construct.
|
|
||
| // ignore unused private method (it's actually used in Stage) | ||
| // @ts-ignore | ||
| private _findInputArtifactFor(stage: actions.IStage, action: actions.Action): actions.Artifact { |
There was a problem hiding this comment.
add doc that describes what this method is doing
| * | ||
| * @param action the Action to find the input artifact for | ||
| */ | ||
| _findInputArtifactFor(action: Action): Artifact; |
| * Finds an input artifact for the given Action | ||
| * among the existing output artifacts currently in the Pipeline. | ||
| * This is an internal operation - | ||
| * you should never need to call it directly. |
There was a problem hiding this comment.
Provide some details on the algorithm
There was a problem hiding this comment.
Done (it's not an easy one to describe...).
b8e701c to
5cc4f3c
Compare
|
Updated with review comments. There are 2 more things that could be nice to change while we're in this area:
protected addChild(child: cdk.Construct, name: string) {
super.addChild(child, name);
if (child instanceof Artifact) {
this._outputArtifacts.push(child);
}
}
protected addOutputArtifact(name: string = this.stage._internal._generateOutputArtifactName(this)): Artifact {
const artifact = new Artifact(this, name);
return artifact;
}It kind of abuses the Construct hierarchy, and I have no idea what these extra artifacts would accomplish - I think Action should only take artifacts as arguments when constructing them. I would like to remove this code. @RomainMuller @eladb thoughts on these 2 points? |
|
Regarding the Regarding the second point, I think I'm okay dropping those if we don't have a clear use-case for them. We can always re-introduce if it turns out to be needed for something that cannot be done another way (unlikely). |
|
@skinny85 I agree that output artifacts should be defined during initialization and we can get rid of |
Can you elaborate on this @RomainMuller ? When can a CodeBuild project produce multiple artifacts? |
|
@RomainMuller ping According to a table in the AWS docs, CodeBuild can have a maximum of 1 output. |
|
@skinny85 well that's interesting... What happens now when your build spec specifies And then, this still leaves me with the question of how do I access this "one" artifact... Right now the only way I found to work is |
I assume they're ignored by CodePipeline.
This is the Do the changes here now make sense? |
|
Thanks for the clarification, @skinny85. I'm cool with this (and sorry the conversation dragged for so long here). |
5cc4f3c to
8280ca1
Compare
|
Rebased & made the two changes we discussed above. |
… when creating Actions. BREAKING CHANGE: this commit contains the following breaking changes: * Rename 'artifactName' in Action construction properties to 'outputArtifactName' * Rename the 'artifact' property of Actions to 'outputArtifact' * No longer allow adding output artifacts to Actions by instantiating the Artifact class * Rename Action#input/outputArtifacts properties to _input/_outputArtifacts Previously, we always required customers to explicitly name the output artifacts the Actions used in the Pipeline, and to explicitly "wire together" the outputs of one Action as inputs to another. With this change, the CodePipeline Construct generates artifact names, if the customer didn't provide one explicitly, and tries to find the first available output artifact to use as input to a newly created Action that needs it, thus turning both the input and output artifacts from required to optional properties.
8280ca1 to
fedc18e
Compare
|
Missed a usage of the old |
No worries, and thanks for the review! |
__IMPORTANT NOTE__: This release includes a [breaking change](#845) in the AWS CodePipeline construct library: * The `inputArtifacts` and `outputArtifacts` properties of `Action` were intended for internal usage only, and have consequently been renamed to `_inputArtifacts` and `_outputArtifacts` respectively. * The `artifact` property of `Action` classes was renamed to `outputArtifact`. * The `artifactName` property of `Action` classes was renamed to `outputArtifactName`. * It is no longer possible to add output artifacts to `Actions` by instantiating `Artifact`. This release also includes a [fix](#911) for a bug that would make the toolkit unusable for multi-stack applications. In order to benefit from this fix, a globally installed CDK toolkit must also be updated: ```shell $ npm i -g aws-cdk $ cdk --version 0.12.0 (build ...) ``` Like always, you will also need to update your project's library versions: |Language|Update?| |--------|-------| |JavaScript/TypeScript (npm)|[`npx npm-check-updates -u`](https://www.npmjs.com/package/npm-check-updates)| |Java (maven)|[`mvn versions:use-latest-versions`](https://www.mojohaus.org/versions-maven-plugin/use-latest-versions-mojo.html) |.NET (NuGet)|[`nuget update`](https://docs.microsoft.com/en-us/nuget/tools/cli-ref-update) * **aws-cdk:** multi-stack apps can be synthesized or deployed [#911](#911). * **@aws-cdk/aws-codebuild:** allow passing oauth token to GitHubEnterpriseSource [#908](#908) * **@aws-cdk/aws-codepipeline:** make input and output artifact names optional when creating Actions. [#845](#945) * **@aws-cdk/aws-cloudformation:** add permission management to CreateUpdate and Delete Stack CodePipeline Actions. [#880](#880)
* **aws-codebuild:** allow passing oauth token to GitHubEnterpriseSource ([#908](#908)) ([c23da91](c23da91)) * **toolkit:** multi-stack apps cannot be synthesized or deployed ([#911](#911)) ([5511076](5511076)), closes [#868](#868) [#294](#294) [#910](#910) * **aws-cloudformation:** add permission management to CreateUpdate and Delete Stack CodePipeline Actions. ([#880](#880)) ([8b3ae43](8b3ae43)) * **aws-codepipeline:** make input and output artifact names optional when creating Actions. ([#845](#845)) ([3d91c93](3d91c93)) * **aws-codepipeline:** this commit contains the following breaking changes: * Rename 'artifactName' in Action construction properties to 'outputArtifactName' * Rename the 'artifact' property of Actions to 'outputArtifact' * No longer allow adding output artifacts to Actions by instantiating the Artifact class * Rename Action#input/outputArtifacts properties to _input/_outputArtifacts Previously, we always required customers to explicitly name the output artifacts the Actions used in the Pipeline, and to explicitly "wire together" the outputs of one Action as inputs to another. With this change, the CodePipeline Construct generates artifact names, if the customer didn't provide one explicitly, and tries to find the first available output artifact to use as input to a newly created Action that needs it, thus turning both the input and output artifacts from required to optional properties.
* **aws-codebuild:** allow passing oauth token to GitHubEnterpriseSource ([#908](#908)) ([c23da91](c23da91)) * **toolkit:** multi-stack apps cannot be synthesized or deployed ([#911](#911)) ([5511076](5511076)), closes [#868](#868) [#294](#294) [#910](#910) * **aws-cloudformation:** add permission management to CreateUpdate and Delete Stack CodePipeline Actions. ([#880](#880)) ([8b3ae43](8b3ae43)) * **aws-codepipeline:** make input and output artifact names optional when creating Actions. ([#845](#845)) ([3d91c93](3d91c93)) * **aws-codepipeline:** this commit contains the following breaking changes: * Rename 'artifactName' in Action construction properties to 'outputArtifactName' * Rename the 'artifact' property of Actions to 'outputArtifact' * No longer allow adding output artifacts to Actions by instantiating the Artifact class * Rename Action#input/outputArtifacts properties to _input/_outputArtifacts Previously, we always required customers to explicitly name the output artifacts the Actions used in the Pipeline, and to explicitly "wire together" the outputs of one Action as inputs to another. With this change, the CodePipeline Construct generates artifact names, if the customer didn't provide one explicitly, and tries to find the first available output artifact to use as input to a newly created Action that needs it, thus turning both the input and output artifacts from required to optional properties.
Previously, we always required customers to explicitly name the output artifacts the Actions used in the Pipeline, and to explicitly "wire together" the outputs of one Action as inputs to another. With this change, the CodePipeline Construct generates artifact names, if the customer didn't provide one explicitly, and tries to find the first available output artifact to use as input to a newly created Action that needs it, thus turning both the input and output artifacts from required to optional properties.
@eladb @RomainMuller I also had one more suggestion. I've always hated the
artifactNameproperty name of the Actions. It's misleading, and inconsistent withinputArtifact. How would you guys feel about a breaking change to rename that property tooutputArtifactName?By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license.